package jinyilw.swing;

import jinyilw.common.app.AppConfig;
import jinyilw.common.file.FileTools;
import jinyilw.common.log.LogTools;
import jinyilw.swing.i18n.ICSetting;
import jinyilw.swing.i18n.LanguageChanger;
import jinyilw.swing.rlaf.theme.UIData;
import jinyilw.swing.visuals.border.AbstractITitleBorder;

import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.plaf.UIResource;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.awt.Window;
import java.io.File;

public class FontTools
{

	public static boolean useSystemFontForEnglish = true;
	static String systemFontName = /* "Default" */ "微软雅黑";
	static Font systemFont = new Font(systemFontName, Font.BOLD, 12);
	private static final Font[] systemFonts = new Font[30];

	private static File customFontFile, currentFontFile;
	private static final int customFontStyle = Font.PLAIN;
	private static final float customFontSize = 12f;

	private static Font originalFont = initFont();
	private static CustomFont[] customFonts = new CustomFont[30];
	public static CustomFont defaultFont = new CustomFont(
			originalFont.deriveFont(12f));
	public static CustomFont tinyFont = new CustomFont(
			originalFont.deriveFont(6f));
	public static int smallFontSize = 8;
	private static Font largeFont;
	private static Font bigFont;
	private static Font frameTitleFont;
	public static int fontIdentifier;

	private static Font initFont()
	{
		AppConfig.addAppExitedOperator( o -> {
			if (currentFontFile != null
					&& customFontFile != currentFontFile)
			{
				FileTools.copyFile(currentFontFile, customFontFile);
				FileTools.setToHidden(customFontFile);
			}
		});
		currentFontFile = customFontFile = FileTools
				.getUserFile("font/.customFont");
		if (customFontFile.isFile())
			try
			{
				return Font.createFont(Font.TRUETYPE_FONT, customFontFile)
						.deriveFont(customFontStyle, customFontSize);
			} catch (Exception e)
			{
				LogTools.debug("创建自定义字体出错!", e);
			}
		return systemFont;
	}

	private FontTools()
	{
	}

	public static Font getLargeFont()
	{
		if (largeFont == null)
		{
			if (customFonts[14] == null)
				customFonts[14] = new CustomFont(originalFont.deriveFont(14f));
			largeFont = customFonts[14];
		}
		return largeFont;
	}

	public static Font getBigFont()
	{
		if (bigFont == null)
		{
			if (customFonts[16] == null)
				customFonts[16] = new CustomFont(originalFont.deriveFont(16f));
			bigFont = customFonts[16];
		}
		return bigFont;
	}

	public static Font getFrameTitleFont()
	{
		if (frameTitleFont == null)
		{
			if (customFonts[19] == null)
				customFonts[19] = new CustomFont(originalFont.deriveFont(19f));
			frameTitleFont = customFonts[19];
		}
		return frameTitleFont;
	}

	public static Font getDialogTitleFont()
	{
		return getBigFont();
	}

	public static synchronized Font getSystemFont(int size)
	{
		if (size >= systemFonts.length)
			return systemFont.deriveFont((float) size);
		if (size < 3)
			size = 3;
		if (systemFonts[size] == null)
			systemFonts[size] = systemFont.deriveFont((float) size);
		return systemFonts[size];
	}

	public static Font getSystemUIFont(int size)
	{
		return new UIFont(getSystemFont(size));
	}

	public static synchronized Font getCustomFont(int size)
	{
		if (size > 200)
			size = 200;
		int l = size + 1 - customFonts.length;
		if (l > 0)
			customFonts = expandFontArray(customFonts, l);
		if (size < 6)
			size = 6;
		if (customFonts[size] == null)
		{
			if (size < 7)
				customFonts[size] = tinyFont;
			else
				customFonts[size] = new CustomFont(
						originalFont.deriveFont((float) size));
		}
		return customFonts[size];
	}

	static CustomFont[] expandFontArray(CustomFont[] src, int increase)
	{
		int size = src.length;
		CustomFont[] dest = new CustomFont[size + increase];
		System.arraycopy(src, 0, dest, 0, size);
		return dest;
	}

	public static void customFontSetting(Component c)
	{
		if (c instanceof LanguageChanger)
		{
			ICSetting i18nSetting = ((LanguageChanger) c).getICSetting();
			if (i18nSetting != null && i18nSetting.isFontChange())
			{
				i18nSetting.changStyleFont(customFonts);
				c.setFont(i18nSetting.getFont(c));
				return;
			}
		}
		Font font = c.getFont();
		if (font instanceof CustomFont)
			c.setFont(
					customFonts[font.getSize()].getStyleFont(font.getStyle()));
	}

	public static void customFontSetting(TitledBorder b, Component c)
	{
		Font font = b.getTitleFont();
		if (font instanceof CustomFont)
		{
			b.setTitleFont(
					customFonts[font.getSize()].getStyleFont(font.getStyle()));
			if (c.isShowing())
				c.repaint();
		}
	}

	public static void customFontSetting(AbstractITitleBorder b, Component c)
	{
		ICSetting i18nTitle = b.getI18nTitle();
		if (i18nTitle != null && i18nTitle.isFontChange())
		{
			i18nTitle.changStyleFont(customFonts);
			if (c.isShowing())
				c.repaint();
			return;
		}
		Font font = b.getTitleFont();
		if (font instanceof CustomFont)
		{
			b.setTitleFont(
					customFonts[font.getSize()].getStyleFont(font.getStyle()));
			if (c.isShowing())
				c.repaint();
		}
	}

	public static void changeDefaultFont(File fontFile)
	{
		Font font;
		try
		{
			font = Font.createFont(Font.TRUETYPE_FONT, fontFile);
		} catch (Exception e)
		{
			e.printStackTrace();
			return;
		}
		changeDefaultFont(font);
		currentFontFile = fontFile;
	}

	public static void changeDefaultFont(Font font)
	{
		if (font == null || font.equals(originalFont)
				|| font instanceof CustomFont)
			return;
		originalFont = font;
		fontIdentifier++;
		changeFonts();
		for (Window w : Window.getWindows())
			updateFont(w);
	}

	private static void changeFonts()
	{
		defaultFont = new CustomFont(originalFont.deriveFont(12f));
		tinyFont = new CustomFont(originalFont.deriveFont(6f));
		for (int i = 0; i < customFonts.length; i++)
			if (i < 7)
				customFonts[i] = tinyFont;
			else
				customFonts[i] = new CustomFont(
						originalFont.deriveFont((float) i));
		largeFont = customFonts[14];
		bigFont = customFonts[16];
		frameTitleFont = customFonts[19];
		UIData.getDefaultUIData().frameUI.titleFont = frameTitleFont;
		UIData.getDefaultUIData().dialogUI.titleFont = bigFont;
		UIManager.put("TitledBorder.font", defaultFont);
	}

	public static void updateFont(Component c)
	{
		customFontSetting(c);
		if (c instanceof JComponent)
		{
			Border border = ((JComponent) c).getBorder();
			if (border != null)
			{
				if (border instanceof TitledBorder)
					customFontSetting((TitledBorder) border, c);
				else if (border instanceof AbstractITitleBorder)
					customFontSetting((AbstractITitleBorder) border, c);
			}
		}
		Component[] children = null;
		if (c instanceof Container)
			children = ((Container) c).getComponents();
		if (children != null)
			for (Component child : children)
				updateFont(child);
	}

	public static void resetDefaultFont()
	{
		changeDefaultFont(systemFont);
		currentFontFile = null;
		if (customFontFile != null)
			customFontFile.delete();
	}

	public static class CustomFont extends UIFont
	{
		private static final long serialVersionUID = 9141422370797827811L;
		private CustomFont boldFont, plainFont, italicFont;
		private boolean styleChanged;

		public CustomFont(String name, int style, int size)
		{
			super(name, style, size);
		}

		public CustomFont(Font font)
		{
			super(font);
		}

		@Override
		public Font deriveFont(int style, float size)
		{
			Font font = getCustomFont((int) size);
			if (this.style == style)
				return font;
			return font.deriveFont(style);
		}

		@Override
		public Font deriveFont(float size)
		{
			return getCustomFont((int) size);
		}

		@Override
		public Font deriveFont(int style)
		{
			if (this.style == style)
				return this;
			styleChanged = true;
			if (style == BOLD)
			{
				if (boldFont == null)
					boldFont = new CustomFont(super.deriveFont(BOLD));
				return boldFont;
			}
			if (style == ITALIC)
			{
				if (italicFont == null)
					italicFont = new CustomFont(super.deriveFont(ITALIC));
				return italicFont;
			}
			if (plainFont == null)
				plainFont = new CustomFont(super.deriveFont(PLAIN));
			return plainFont;
		}

		public Font getStyleFont(int style)
		{
			if (styleChanged)
				return deriveFont(style);
			return this;
		}
	}

	public static class UIFont extends Font implements UIResource
	{
		private static final long serialVersionUID = 4823859852024282318L;

		public UIFont(String name, int style, int size)
		{
			super(name, style, size);
		}

		public UIFont(Font font)
		{
			super(font);
		}

		@Override
		public Font deriveFont(float size)
		{
			return new UIFont(super.deriveFont(size));
		}
	}

	//	public static void initGlobalFont(Font font)
	//	{
	//		FontUIResource fontRes = new FontUIResource(font);
	//		for (Enumeration<Object> keys = UIManager.getDefaults().keys(); keys
	//				.hasMoreElements();)
	//		{
	//			Object key = keys.nextElement();
	//			Object value = UIManager.get(key);
	//			if (value instanceof FontUIResource)
	//				UIManager.put(key, fontRes);
	//		}
	//	}
	//
	//	public static void setUIFont(Font font)
	//	{
	//		FontUIResource fontRes = new FontUIResource(font);
	//		String names[] = {"Label", "CheckBox", "PopupMenu", "MenuItem",
	//				"CheckBoxMenuItem", "JRadioButtonMenuItem", "ComboBox",
	//				"Button", "Tree", "ScrollPane", "TabbedPane", "EditorPane",
	//				"TitledBorder", "Menu", "TextArea", "OptionPane", "MenuBar",
	//				"ToolBar", "ToggleButton", "ToolTip", "ProgressBar",
	//				"TableHeader", "Panel", "List", "ColorChooser", "PasswordField",
	//				"TextField", "Table", "Label", "Viewport",
	//				"RadioButtonMenuItem", "RadioButton", "DesktopPane",
	//				"InternalFrame"};
	//		for (String item : names)
	//			UIManager.put(item + ".font", fontRes);
	//	}
}
